package com.neusoft.databus.agent.utils;

import java.io.InterruptedIOException;
import java.net.UnknownHostException;

import javax.net.ssl.SSLException;
import javax.net.ssl.SSLHandshakeException;

import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpEntityEnclosingRequest;
import org.apache.http.HttpHost;
import org.apache.http.HttpRequest;
import org.apache.http.NoHttpResponseException;
import org.apache.http.client.HttpRequestRetryHandler;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.ConnectTimeoutException;
import org.apache.http.conn.routing.HttpRoute;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.LayeredConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;

public class HttpClientUtil {

    private static String hostname = "";
    private static int port = 0;
    static final int timeOut = 10 * 1000;

    private static CloseableHttpClient httpClient = null;

    private final static Object syncLock = new Object();

    public static void initialize(final String hostname, final int port) {
        HttpClientUtil.hostname = hostname;
        HttpClientUtil.port = port;
    }

    public static String getBaseUrl() {
        return "http://" + HttpClientUtil.hostname + ":" + HttpClientUtil.port;
    }

    public static CloseableHttpClient getHttpClient() throws UnknownHostException {
        if (StringUtils.isEmpty(HttpClientUtil.hostname)) {
            throw new UnknownHostException("请设置服务地址");
        }
        if (HttpClientUtil.port == 0) {
            throw new IllegalArgumentException("请设置服务端口");
        }
        if (HttpClientUtil.httpClient == null) {
            synchronized (HttpClientUtil.syncLock) {
                if (HttpClientUtil.httpClient == null) {
                    HttpClientUtil.httpClient =
                            HttpClientUtil.createHttpClient(200, 40, 100, HttpClientUtil.hostname, HttpClientUtil.port);
                }
            }
        }
        return HttpClientUtil.httpClient;
    }

    public static CloseableHttpClient createHttpClient(final int maxTotal,
            final int maxPerRoute, final int maxRoute, final String hostname, final int port) {
        final ConnectionSocketFactory plainsf = PlainConnectionSocketFactory
                .getSocketFactory();
        final LayeredConnectionSocketFactory sslsf = SSLConnectionSocketFactory
                .getSocketFactory();
        final Registry<ConnectionSocketFactory> registry = RegistryBuilder
                .<ConnectionSocketFactory> create().register("http", plainsf)
                .register("https", sslsf).build();
        final PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager(
                registry);
        // 将最大连接数增加
        cm.setMaxTotal(maxTotal);
        // 将每个路由基础的连接增加
        cm.setDefaultMaxPerRoute(maxPerRoute);
        final HttpHost httpHost = new HttpHost(hostname, port);
        // 将目标主机的最大连接数增加
        cm.setMaxPerRoute(new HttpRoute(httpHost), maxRoute);

        // 请求重试处理
        final HttpRequestRetryHandler httpRequestRetryHandler = (exception, executionCount, context) -> {
            if (executionCount >= 5) {// 如果已经重试了5次，就放弃
                return false;
            }
            if (exception instanceof NoHttpResponseException) {// 如果服务器丢掉了连接，那么就重试
                return true;
            }
            if (exception instanceof SSLHandshakeException) {// 不要重试SSL握手异常
                return false;
            }
            if (exception instanceof InterruptedIOException) {// 超时
                return false;
            }
            if (exception instanceof UnknownHostException) {// 目标服务器不可达
                return false;
            }
            if (exception instanceof ConnectTimeoutException) {// 连接被拒绝
                return false;
            }
            if (exception instanceof SSLException) {// SSL握手异常
                return false;
            }

            final HttpClientContext clientContext = HttpClientContext
                    .adapt(context);
            final HttpRequest request = clientContext.getRequest();
            // 如果请求是幂等的，就再次尝试
            if (!(request instanceof HttpEntityEnclosingRequest)) {
                return true;
            }
            return false;
        };

        final CloseableHttpClient httpClient = HttpClients.custom()
                .setConnectionManager(cm)
                .setRetryHandler(httpRequestRetryHandler).build();

        return httpClient;
    }

}
